/*
 *游戏服务器列表
 */
package labox.innovation.loginserver;

import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

import javolution.util.FastMap;
import labox.innovation.config.Config;
import labox.innovation.db.core.L2DatabaseFactory;
import labox.innovation.loginserver.gameserverpackets.ServerStatus;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author KenM
 */
public class GameServerTable {
	
	private static Logger _log = LoggerFactory.getLogger(GameServerTable.class.getName());

	private static GameServerTable _instance;

	// Game Server Table
	private Map<Integer, GameServerInfo> _gameServerTable = new FastMap<Integer, GameServerInfo>().shared();

	// RSA Config
	//private static final int KEYS_SIZE = 10;

	public static void load() throws SQLException, GeneralSecurityException {
		synchronized (GameServerTable.class) {
			if (_instance == null) {
				_instance = new GameServerTable();
			} else {
				throw new IllegalStateException("Load can only be invoked a single time.");
			}
		}
	}

	public static GameServerTable getInstance() {
		return _instance;
	}

	public GameServerTable() throws SQLException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
		loadRegisteredGameServers(); //-- 读取已经注册游戏服务器列表到内存
		_log.info("Loaded " + _gameServerTable.size() + " registered Game Servers");
	}

	/**
	 * 从数据库中载入当前已经注册游戏服务器列表
	 * 
	 * @throws SQLException
	 */
	private void loadRegisteredGameServers() throws SQLException {
		Connection con = null;
		PreparedStatement statement = null;

		int id;
		con = L2DatabaseFactory.getInstance().getConnection();
		statement = con.prepareStatement("SELECT * FROM gameservers");
		ResultSet rset = statement.executeQuery();
		GameServerInfo gsi;
		while (rset.next()) {
			id = rset.getInt("server_id");
			gsi = new GameServerInfo(id);
			gsi.setExternalIp(rset.getString("externalIP"));
			gsi.setExternalHost(rset.getString("host"));
			gsi.setInternalIp(rset.getString("internalIP"));
			gsi.setType(rset.getByte("server_type"));
			_gameServerTable.put(id, gsi);
		}
		rset.close();
		statement.close();
		con.close();
	}

	/**
	 * 获取游戏服列表
	 * 
	 * @return
	 */
	public Map<Integer, GameServerInfo> getRegisteredGameServers() {
		return _gameServerTable;
	}

	/**
	 * 根据游戏服ID获取游戏服内部类实例
	 * 
	 * @param id
	 * @return
	 */
	public GameServerInfo getRegisteredGameServerById(int id) {
		return _gameServerTable.get(id);
	}

	/**
	 * 根据ID判断游戏服是否在游戏服务器注册列表内。
	 * 
	 * @param id
	 * @return
	 */
	public boolean hasRegisteredGameServerOnId(int id) {
		return _gameServerTable.containsKey(id);
	}

	public boolean registerWithFirstAvaliableId(GameServerInfo gsi) {
		synchronized (_gameServerTable) {
			if (!_gameServerTable.containsKey(gsi.getId())) {
				_gameServerTable.put(gsi.getId(), gsi);
				return true;
			}
		}
		return false;
	}

	/**
	 * 注册新游戏服到游戏服内存列表中。
	 * 
	 * @param gsi
	 * @return
	 */
	//	public boolean registerWithFirstAvaliableId(GameServerInfo gsi) {
	//		// avoid two servers registering with the same "free" id
	//		//-- 避免两个游戏服务器使用同一个ID注册。注册从XML配置文件中读取的游戏服务器
	//		synchronized (_gameServerTable) {
	//			for (Entry<Integer, String> entry : _serverNames.entrySet()) {
	//				if (!_gameServerTable.containsKey(entry.getKey())) {
	//					_gameServerTable.put(entry.getKey(), gsi);
	//					gsi.setId(entry.getKey());
	//					return true;
	//				}
	//			}
	//		}
	//		return false;
	//	}

	/**
	 * 根据ID注册新游戏服到游戏服内存列表中。
	 * 
	 * @param id
	 * @param gsi
	 * @return
	 */
	public boolean register(int id, GameServerInfo gsi) {
		// avoid two servers registering with the same id
		synchronized (_gameServerTable) {
			if (!_gameServerTable.containsKey(id)) {
				_gameServerTable.put(id, gsi);
				gsi.setId(id);
				return true;
			}
		}
		return false;
	}

	/**
	 * 注册游戏服到后台数据库中。
	 * 
	 * @param gsi
	 */
	public void registerServerOnDB(GameServerInfo gsi) {
		registerServerOnDB(gsi.getId(), gsi.getExternalHost(), gsi.getType(), gsi.getInternalIp(), gsi.getExternalIp());
	}

	/**
	 * 写数据库操作，添加新游戏服务器
	 * 
	 * @param id
	 * @param externalHost
	 */
	public void registerServerOnDB(int id, String externalHost, int type, String internalIP, String externalIP) {
		Connection con = null;
		PreparedStatement statement = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			statement = con.prepareStatement("INSERT INTO gameservers (server_id,host,server_type,internalIP,externalIP) values (?,?,?,?,?)");
			statement.setInt(1, id);
			statement.setString(2, externalHost);
			statement.setInt(3, type);
			statement.setString(4, internalIP);
			statement.setString(5, externalIP);
			statement.executeUpdate();
			statement.close();
		} catch (SQLException e) {
			_log.error("SQL error while saving gameserver.", Config.SERVER_ID, e);
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
	}

	public void updateServerOnDB(GameServerInfo gsi) {
		updateServerOnDB(gsi.getId(), gsi.getExternalHost(), gsi.getType(), gsi.getExternalIp());
	}

	private void updateServerOnDB(int id, String externalHost, int type, String externalIP) {
		Connection con = null;
		PreparedStatement statement = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			statement = con.prepareStatement("UPDATE gameservers set host = ?,server_type = ?,externalIP=? where server_id=?");
			statement.setString(1, externalHost);
			statement.setInt(2, type);
			statement.setString(3, externalIP);
			statement.setInt(4, id);
			statement.executeUpdate();
			statement.close();
		} catch (SQLException e) {
			_log.error("SQL error while saving gameserver.", Config.SERVER_ID, e);
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
	}

	/**
	 * 游戏服务器描述内部类
	 * 
	 * @author
	 * 
	 */
	public static class GameServerInfo {
		// auth
		private int _id;

		private boolean _isAuthed;

		// status
		private GameServerThread _gst;

		/**
		 * 服务器状态：0维护（维护状态）、1正常（500人以下）、2繁忙（单服500人以上）、3爆满（达到单服人数上限）,4 GM服务器
		 */
		private int _status;

		// network
		private String _internalIp;

		private String _externalIp;

		private String _externalHost;

		private int _port;

		private boolean _isTestServer;

		private boolean _isShowingClock;

		private boolean _isShowingBrackets;

		private int _maxPlayers;

		/**
		 * 服务器类型：0普通服、1新服、2推荐服
		 */
		private int _type;

		private int _playCount;

		/**
		 * 构造方法
		 * 
		 * @param id
		 * @param gst
		 */
		public GameServerInfo(int id, GameServerThread gst) {
			_id = id;
			_gst = gst;
			_status = ServerStatus.STATUS_DOWN;
		}

		public GameServerInfo(int id) {
			this(id, null);
		}

		public void setId(int id) {
			_id = id;
		}

		public int getId() {
			return _id;
		}

		public void setAuthed(boolean isAuthed) {
			_isAuthed = isAuthed;
		}

		public boolean isAuthed() {
			return _isAuthed;
		}

		public void setGameServerThread(GameServerThread gst) {
			_gst = gst;
		}

		public GameServerThread getGameServerThread() {
			return _gst;
		}

		public void setStatus(int status) {
			_status = status;
		}

		public int getStatus() {
			return _status;
		}

		public int getCurrentPlayerCount() {
			if (_gst == null)
				return 0;
			return _gst.getPlayerCount();
		}

		public void setInternalIp(String internalIp) {
			_internalIp = internalIp;
		}

		public String getInternalIp() {
			return _internalIp;
		}

		public void setExternalIp(String externalIp) {
			_externalIp = externalIp;
		}

		public String getExternalIp() {
			return _externalIp;
		}

		public void setExternalHost(String externalHost) {
			_externalHost = externalHost;
		}

		public String getExternalHost() {
			return _externalHost;
		}

		public int getPort() {
			return _port;
		}

		public void setPort(int port) {
			_port = port;
		}

		public void setMaxPlayers(int maxPlayers) {
			_maxPlayers = maxPlayers;
		}

		public int getMaxPlayers() {
			return _maxPlayers;
		}

		public void setTestServer(boolean val) {
			_isTestServer = val;
		}

		public boolean isTestServer() {
			return _isTestServer;
		}

		public void setShowingClock(boolean clock) {
			_isShowingClock = clock;
		}

		public boolean isShowingClock() {
			return _isShowingClock;
		}

		public void setShowingBrackets(boolean val) {
			_isShowingBrackets = val;
		}

		public int getType() {
			return _type;
		}

		public void setType(int type) {
			_type = type;
		}

		public int getPlayCount() {
			return this._playCount;
		}

		public void setPlayCount(int playCount) {
			this._playCount = playCount;
		}

		public boolean isShowingBrackets() {
			return _isShowingBrackets;
		}

		/**
		 * 卸载
		 */
		public void setDown() {
			setAuthed(false);
			setPort(0);
			setGameServerThread(null);
			setStatus(ServerStatus.STATUS_DOWN);
		}
	}
}
